package cemp.shiro;

import cemp.jwt.JwtTokenUtil;
import cemp.redis.constant.RedisKey;
import cemp.redis.util.RedisUtils;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

/**
 * @author Yorke
 */
@Component
public class ShiroCustomRealm extends AuthorizingRealm {

    @Autowired
    RedisUtils redisUtils;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof OAuth2Token;
    }
    /**
     * 认证
     * (判断是否登录的一个方法。每一次请求都需要判断是否需要登录)
     * 1. 比对 token == redis(token) ? shiro的分布式
     * 2. 对 token(jwt) parse 成认证对象Claims
     * 3. return SimpleAuthenticationInfo 告知shiro 用户信息 （比如权限方面的用于controller中的权限拦截等功能 ，本案例中不适用shiro自身的权限功能，）
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//        /* cookie方式 */
//        UsernamePasswordToken token2 = (UsernamePasswordToken) token;
//        String username = token2.getUsername();
//        String password = "123456";
//        return new SimpleAuthenticationInfo(username, password, getName());

        String accessToken = (String) token.getPrincipal();
        Long userId;
        try {
            Claims claims = JwtTokenUtil.parseJWT(accessToken);
            userId = ((Integer)claims.get("userid")).longValue() ;
            //匹配 redis
            String key = RedisKey.STOCK_AUTH_USER.concat(userId.toString());
            Optional oToken = Optional.ofNullable(redisUtils.get(key));

            String rToken = oToken.isPresent() ? oToken.get().toString() : "";
            if( !rToken.equals(accessToken)){
                throw new IncorrectCredentialsException("token失效，请重新登录");
            }
            String openid = claims.get("openid").toString();
            Gson gson = new Gson();

            //String  permsSetString = ( String )redisTemplate.opsForValue().get(RedisPrefix.SHIROPERFIX +openid);
            //Set<String> permsSet=  gson.fromJson(permsSetString,Set.class);
            Set<String> permsSet = new HashSet<>();
            permsSet.add("query");
            permsSet.add("delete");
            SysUserPermission user = new SysUserPermission();
            user.setUserId(userId);
            user.setOpenid(openid);
            user.setPermissions(permsSet);
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName());
            return info;
        }catch (ExpiredJwtException e){
            throw new IncorrectCredentialsException("token过期，请重新登录");
        }catch (Exception e) {
            e.printStackTrace();
            /**
             * 应该抛出异常 而不是return return有点问题
             */
            throw new IncorrectCredentialsException("token有误，请重新登录");
//            return null;
        }
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = (String) super.getAvailablePrincipal(principalCollection);
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Set<String> roles = new HashSet<>();
        roles.add("find");
        authorizationInfo.setRoles(roles);
        roles.forEach(role -> {
            Set<String> permissions = new HashSet<>();
            permissions.add("find1");
            permissions.add("find2");
            authorizationInfo.addStringPermissions(permissions);
        });
        return authorizationInfo;
    }
}
